/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.leakcanary;

import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static com.squareup.leakcanary.LeakCanary.leakInfo;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.json.JSONArray;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import com.wbtech.ums.AppInfo;
import com.wbtech.ums.CommonUtil;
import com.wbtech.ums.DeviceInfo;
import com.wbtech.ums.UmsAgent.SendPolicy;
import com.wbtech.ums.UmsConstants;

/**
 * Logs leak analysis results, and then shows a notification which will start
 * {@link DisplayLeakActivity}.
 * 
 * You can extend this class and override
 * {@link #afterDefaultHandling(HeapDump, AnalysisResult, String)} to add custom
 * behavior, e.g. uploading the heap dump.
 */
public class DisplayLeakService extends AbstractAnalysisResultService {
	public static final String TAG = "LeakCanary";
	public static final int SHOW_RESPONSE = 0;
	public static final String LEAK_URL = "/ums/postLeakcanryLog";

	@TargetApi(HONEYCOMB)
	@Override
	protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
		String leakInfo = leakInfo(this, heapDump, result, true);
		if (leakInfo.length() < 4000) {
			Log.d("LeakCanary", leakInfo);
		} else {
			String[] lines = leakInfo.split("\n");
			for (String line : lines) {
				Log.d("LeakCanary", line);
			}
		}

		if (result.failure == null
				&& (!result.leakFound || result.excludedLeak)) {
			afterDefaultHandling(heapDump, result, leakInfo);
			return;
		}

		afterDefaultHandling(heapDump, result, leakInfo);
	}

	/**
	 * You can override this method and do a blocking call to a server to upload
	 * the leak trace and the heap dump. Don't forget to check
	 * {@link AnalysisResult#leakFound} and {@link AnalysisResult#excludedLeak}
	 * first.
	 */
	@SuppressLint("NewApi")
	protected void afterDefaultHandling(HeapDump heapDump,
			AnalysisResult result, String leakInfo) {
		Log.d("DisplayLeakService", "DisplayLeakService:afterDefaulthandling ");
		Log.d(TAG, "afterDefaultHandling: here");
		if (!result.leakFound || result.excludedLeak) {
			return;
		}

		// use JSONObject to save info
		JSONObject uploadObject = new JSONObject(); // 最终上传的JSONObject
		JSONArray leakArray = new JSONArray();
		JSONObject leakObject = new JSONObject();
		
		try {
			// package info
			PackageManager packageManager = this.getPackageManager();
			String packageName = this.getPackageName();

			PackageInfo packageInfo;
			try {
				packageInfo = packageManager.getPackageInfo(packageName, 0);
			} catch (PackageManager.NameNotFoundException var11) {
				throw new RuntimeException(var11);
			}

			String versionName = packageInfo.versionName;
			int versionCode = packageInfo.versionCode;

			// leakObject.put("packageName", packageName);
			leakObject.put("versionName", versionName);
			leakObject.put("versionCode", String.valueOf(versionCode));

			// device info
			leakObject.put("device", DeviceInfo.getDeviceName());
			leakObject.put("brand", Build.BRAND);
			leakObject.put("product", Build.PRODUCT);

			// android info
			leakObject.put("os_version", Build.VERSION.RELEASE);
			leakObject.put("api", String.valueOf(Build.VERSION.SDK_INT));

			// error brief info
			String briefInfo = "";
			if (result.leakFound) {
				if (result.excludedLeak) {
					briefInfo = briefInfo + "* LEAK CAN BE IGNORED.\n";
				}

				briefInfo = briefInfo + "* " + result.className;
				if (!heapDump.referenceName.equals("")) {
					briefInfo = briefInfo + " (" + heapDump.referenceName + ")";
				}

				briefInfo = briefInfo + " has leaked:\n"
						+ result.leakTrace.toString() + "\n";

			} else if (result.failure != null) {
				briefInfo = briefInfo + "* FAILURE:\n"
						+ Log.getStackTraceString(result.failure) + "\n";
			} else {
				briefInfo = briefInfo + "* NO LEAK FOUND.\n\n";
			}
			leakObject.put("briefInfo", briefInfo);

			// error detail info
			String detailedInfo = result.leakTrace.toDetailedString();

			leakObject.put("detailInfo", detailedInfo);

			// current time
			Date nowTime = new Date();
			SimpleDateFormat format = new SimpleDateFormat(
					"yyyy-MM-dd HH:mm:ss");
			String time = format.format(nowTime);
			leakObject.put("time", time);

			// read appkey from AndroidManifest
			AppInfo.init(this);
			String appKey = AppInfo.getAppKey();
			leakObject.put("appkey", appKey);

			// other key
			leakObject.put("isfix", String.valueOf(0));

			// 最终上传的json格式
			leakArray.put(leakObject);
			uploadObject.put("appkey", appKey);
			uploadObject.put("leakInfo", leakArray);

		} catch (Exception e) {
			// TODO: handle exception
		}

		// send info to server
		// String postUrl = "http://10.16.12.45/sem/post.php";
		String postUrl = UmsConstants.urlPrefix + LEAK_URL;
		sendPostURLConnection(postUrl, uploadObject, leakObject);
	}

	/*private Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case SHOW_RESPONSE:
				String response = (String) msg.obj;
				// make toast
				Toast.makeText(DisplayLeakService.this, response,
						Toast.LENGTH_SHORT).show();
			}
		}
	};*/

	private void sendPostURLConnection(final String url,
			final JSONObject uploadObject, final JSONObject saveObject) {

		new Thread() {
			public void run() {
				Context context = DisplayLeakService.this
						.getApplicationContext();
				if (CommonUtil.getReportPolicyMode(context) == SendPolicy.REALTIME
						&& CommonUtil.isNetworkAvailable(context)) {
					post(url, uploadObject, saveObject, context);
				} else {
					CommonUtil.saveInfoToFile("leakInfo", saveObject,
							"/leakInfo.cache", context);
				}
			};
		}.start();
	}

	private void post(String path, JSONObject uploadObject,
			JSONObject saveObject, Context context) {
		if (uploadObject.length() > 0) {
			Log.d(TAG, "run: " + uploadObject.length());
			HttpURLConnection conn = null;

			try {
				URL url = new URL(path);
				conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod("POST");
				conn.setConnectTimeout(5 * 1000);
				conn.setReadTimeout(5 * 1000);

				conn.setDoOutput(true); // if use post, must set the
										// DoOutput true
				conn.setDoInput(true);
				conn.setUseCaches(false); // cancel user cache
				conn.setRequestProperty("Content-Type",
						"application/x-www-form-urlencoded");

				// build connection
				conn.connect();

				DataOutputStream outputStream = new DataOutputStream(
						conn.getOutputStream());
				String entityData = "content="
						+ URLEncoder.encode(uploadObject.toString(), "UTF-8");
				outputStream.writeBytes(entityData);
				outputStream.flush();
				outputStream.close();

				// the response code
				int code = conn.getResponseCode();
				if (code == HttpURLConnection.HTTP_OK) {
					Log.d(TAG, "run: send success");
					InputStream inputStream = conn.getInputStream();
					String resData = null;
					ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
					byte[] datas = new byte[1024];
					int len = 0;
					while ((len = inputStream.read(datas)) != -1) {
						byteArrayOutputStream.write(datas, 0, len);
					}

					resData = new String(byteArrayOutputStream.toByteArray());
					Log.d(TAG, "run response: " + resData);
					inputStream.close();

					/*Message message = new Message();
					message.what = SHOW_RESPONSE;
					message.obj = "send success, code = 200";
					handler.sendMessage(message);*/
				} else {
					CommonUtil.saveInfoToFile("leakInfo", saveObject,
							"/leakInfo.cache", context);
					Log.d(TAG, "run: send failed, code =" + code);
				/*	Message message = new Message();
					message.what = SHOW_RESPONSE;
					message.obj = "send failed, code = " + code;
					handler.sendMessage(message);*/
				}

			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (conn != null) {
					conn.disconnect();
				}
			}
		}
	}
}
